
/**
 * 指定一个ESP8266驱动一个步进电机
 * @param {device} device 目标ESP8266开发板
 * @param {number} pwnPin 脉冲引脚
 * @param {number} directionPin 方向引脚
 * @param {number} enablePin 使能引脚
 * 
 */
function StepMotor(device, pwnPin, directionPin, enablePin) {
    this.device = device
    this.id = Math.round(Math.random() * 100000)
    this.sleep = 20

    this.homepin = -1
    this.homdSnr = LOW

    //当前位置
    this.position = 0
    //当前位置的缓存
    this.position_cache = 0
    //最大行程
    this.max = 1000000
    //最小行程
    this.min = 0
    //当前位置的缓存
    this.position_cache = 0

    /**
     * 是否回原点了
     */
    this.homed = true

    //加减速度
    this.acc = false

    //最低和最该速度
    this.lowspeed = -1
    this.highspeed = -1
    this.stage = 10

    /**
     * 是否上电了
     */
    this.oned = false

    this.command = new Command().id(this.id).build()
    /**
     * 添加旋转参数
     * @param {number} pwn 旋转的 脉冲数
     * @param {number} dir 旋转的方向
     * 
     */
    this.add = function (pwn, dir) {

        if (dir == HIGH) {
            this.position_cache += pwm
        } else {
            this.position_cache -= pwm
        }

        var first = new Command().add(Write(directionPin, dir)).id(-1)
        var cadd = new Command()
            .add(Write(pwnPin, HIGH))
            .add(DelayMicroseconds(this.sleep))
            .add(Write(pwnPin, LOW))
            .add(DelayMicroseconds(this.sleep)).id(-1)
            .exit(pwn)
        this.command += (first.build() + cadd.build())
    }



    /**
     * 
     * @param {num} pin 原点传感器IO引脚
     * @param {num} ison 高电平触发还是低电平触发
     */
    this.setHomePin = function (pin, ison) {
        this.homepin = pin
        this.homdSnr = ison
    }


    /**
     * 是否启用缓冲减震
     * @param acc 加速度
     * @param dec 减速度
     */
    this.setStabilize = function (acc, lowspeed, highspeed, stage) {
        this.acc = acc == true
        this.lowspeed = lowspeed == undefined ? 300 : lowspeed
        this.highspeed = highspeed == undefined ? 300 : highspeed
        this.stage = stage == undefined ? 10 : stage
    }


    /**
     * 
     * @param {boolean} enable 是否上电 
     */
    this.on = function (enable) {
        this.command = new Command().id(this.id).build()
        var first = new Command().add(Write(enablePin, !enable ? HIGH : LOW)).id(-1)
        this.command += first.build()
        this.oned = enable
        this.homed = false
        this.start()
    }


    /**
     * 
     * @param {number} dir 方向 
     * @param {number} pwm 脉冲数
     * @param {number} sleep 速度间隔
     */
    this.run = function (pwm, dir, sleep_) {
        if (!this.homed) {
            throw "StepMotor Not Homed"
        }
        if (!this.oned) {
            throw "StepMotor Not Ready"
        }
        this.command = new Command().id(this.id).build()
        var d = sleep_ == undefined ? this.sleep : sleep_
        if ((pwm > 10 * this.stage && d <= 300)) {
            if (this.acc && this.lowspeed != -1 && this.highspeed != -1 && this.stage > 1) {
                var maxspeedpwm = pwm - 20 * this.stage
                var cha = Math.floor((this.lowspeed - d) / this.stage)
                for (var i = 0; i < this.stage; i++) {
                    this.sleep = Math.floor(this.lowspeed - cha * i)
                    this.add(10, dir)
                }
                this.sleep = d
                this.add(maxspeedpwm, dir)
                for (var i = 1; i < this.stage; i++) {
                    this.sleep = Math.floor(cha * i)
                    this.add(10, dir)
                }
                this.start()
                return
            }
        }
        this.sleep = d
        this.add(pwm, dir)
        this.start()
    }


/**
 * 回原点
 */
    this.home = function () {
        if (!this.oned) {
            throw "StepMotor Not Ready"
        }
        if (this.position >= 0) {
            this.command = new Command().id(this.id).build()
            var first = new Command().add(Write(directionPin, LOW)).id(-1)
            var cadd = new Command()
                .add(Write(pwnPin, HIGH))
                .add(DelayMicroseconds(300))
                .add(Write(pwnPin, LOW))
                .add(DelayMicroseconds(300)).id(-1)
                .exit(Read(this.homepin, this.homdSnr))
            this.command += (first.build() + cadd.build())
            sendCommand(this.command, device)
            this.homed = true
            this.position_cache = 0
            this.position = this.position_cache
        }
    }

    this.start = function () {
        sendCommand(this.command, device)
        this.command = new Command().id(this.id).build()
        if (this.position_cache > this.max || this.position_cache < this.min) {
            this.on(false)
            this.position_cache = 0
            this.position = this.position_cache
            throw "StepMotor Not Ready"
        }
        this.position = this.position_cache
    }
    var cmd_ = new Command().add(Mode(pwnPin, OUTPUT))
        .add(Mode(directionPin, OUTPUT))
        .add(Mode(enablePin, OUTPUT))
        .add(Write(enablePin, HIGH)).build()
    sendCommand(cmd_, device)
}